package fafmessenger_server.boundary;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
import java.util.ArrayList;

import fafmessenger_server.control.Controller;
import fafmessenger_server.entity.Message;
import fafmessenger_server.entity.Response;

public class ClientConnection extends Thread {

	private Controller controller;
	private Socket socket;
	private BufferedReader inFromClient;
	private DataOutputStream outToClient;
	private final String CRLF = "\r\n";
	
	public ClientConnection(Controller c, Socket s) throws IOException {
		controller = c;
		socket = s;
		inFromClient = new BufferedReader(new InputStreamReader(socket.getInputStream()));
		outToClient = new DataOutputStream(socket.getOutputStream());
	}
	
	public void run() {
		try {
			String request = inFromClient.readLine();
			GUI.writeLineToConsole("C: " + request);
			
			if (request != null) {
				String type = request.substring(request.indexOf(" ") + 1);
				
				if (type.equals("register")) {
					parseRegisterRequest();
				} else if (type.equals("getmessages")) {
					parseGetMessagesRequest();
				} else if (type.equals("sendmessage")) {
					parseSendMessageRequest();
				}
			}
			
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				socket.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
	
	private void parseRegisterRequest() {
		try {
			String request = inFromClient.readLine();
			GUI.writeLineToConsole("C: " + request + "\n");
			String mobilenumber = request.substring(request.indexOf(" ") + 1);
			
			Response r = controller.register(mobilenumber);	
			
			sendResponse(r);
			
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	private void parseGetMessagesRequest() {
		try {
			String request = inFromClient.readLine();
			GUI.writeLineToConsole("C: " + request);
			String mobilenumber = request.substring(request.indexOf(" ") + 1);
			
			request = inFromClient.readLine();
			GUI.writeLineToConsole("C: " + request + "\n");
			String timestamp = request.substring(request.indexOf(" ") + 1);
			
			Object result = controller.getMessages(mobilenumber, timestamp);
			
			if (result instanceof ArrayList<?>) {
				sendMessages((ArrayList<Message>)result);
			} else {
				sendResponse((Response)result);
			}
			
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	private void parseSendMessageRequest() {
		try {
			String request = inFromClient.readLine();
			GUI.writeLineToConsole("C: " + request);
			String fromMobilenumber = request.substring(request.indexOf(" ") + 1);
			
			request = inFromClient.readLine();
			GUI.writeLineToConsole("C: " + request);
			String toMobilenumber = request.substring(request.indexOf(" ") + 1);
			
			request = inFromClient.readLine();
			GUI.writeLineToConsole("C: " + request + "\n");
			String body = request.substring(request.indexOf(" ") + 1);
			
			Response r = controller.sendMessage(fromMobilenumber, toMobilenumber, body);
			
			sendResponse(r);
			
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	private boolean sendMessages(ArrayList<Message> messages) {
		boolean returnvalue = false;
		
		try {
			outToClient.writeBytes("TYPE: messages" + CRLF);
			GUI.writeLineToConsole("S: TYPE: messages");
			
			for (Message m : messages) {
				outToClient.writeBytes("FROM: " + m.getFromMobilenumber() + CRLF);
				outToClient.writeBytes("TO: " + m.getToMobilenumber() + CRLF);
				outToClient.writeBytes("TIMESTAMP: " + m.getTimestamp().toString() + CRLF);
				outToClient.writeBytes("BODY: " + m.getBody() + CRLF);
				
				GUI.writeLineToConsole("S: FROM: " + m.getFromMobilenumber());
				GUI.writeLineToConsole("S: TO: " + m.getToMobilenumber());
				GUI.writeLineToConsole("S: TIMESTAMP: " + m.getTimestamp().toString());
				GUI.writeLineToConsole("S: BODY: " + m.getBody() + "\n");
			}

			outToClient.writeBytes("END" + CRLF);
			GUI.writeLineToConsole("S: END\n");
			
			outToClient.flush();
			returnvalue = true;
			
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		return returnvalue;
	}
	
	private boolean sendResponse(Response response) {
		boolean returnvalue = false;
		
		try {
			outToClient.writeBytes("TYPE: response" + CRLF);
			outToClient.writeBytes("ID: " + response.getID() + CRLF);
			outToClient.writeBytes("RESULT: " + response.getResult() + CRLF);
			outToClient.writeBytes("DESCRIPTION: " + response.getDescription() + CRLF);
			
			GUI.writeLineToConsole("S: TYPE: response");
			GUI.writeLineToConsole("S: ID: " + response.getID());
			GUI.writeLineToConsole("S: RESULT: " + response.getResult());
			GUI.writeLineToConsole("S: DESCRIPTION: " + response.getDescription() + "\n");
			
			outToClient.flush();
			returnvalue = true;
			
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		return returnvalue;
	}
}
